<?php

namespace App\Recharge\Logic;

use App\Jobs\MerchantZuHeJob;
use App\Jobs\ZuheJob;
use App\Models\H5CombinedOrders;
use App\Models\XnBatchOrder;
use App\Recharge\Bean\ApiNotifyDataBean;
use App\Recharge\Enums\ApiGroupEnum;
use App\Recharge\Exceptions\CyclePunch\OrderIsNotInRechargeException;
use App\Recharge\Exceptions\CyclePunch\OrderNotFoundException;
use App\Recharge\Library;
use Exception;
use Illuminate\Support\Facades\DB;
use Throwable;
use App\Traits\Create;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use App\Jobs\OrderCallbackNotify;
use Illuminate\Support\Facades\Log;
use App\Recharge\Traits\RechargeTraits;
use App\Recharge\Interfaces\ApiInterface;
use App\Models\InterfaceConfiguration;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use function Illuminate\Events\queueable;


class ApiNotifyLogic
{
    use RechargeTraits, Create;

    /**
     * @var ?ApiNotifyDataBean
     */
    public ?ApiNotifyDataBean $bean = null;

    /**
     * @var InterfaceConfiguration|null
     */
    public ?InterfaceConfiguration $api = null;

    /**
     * @param Request $request
     * @param string $en
     */
    public function __construct(public Request $request, public string $en)
    {

    }

    /**
     * @return JsonResponse|mixed
     */
    public function send(): mixed
    {
        try {
            $this->api = InterfaceConfiguration::query()->firstWhere('en', $this->en);
            if (!$this->api) {
                throw new Exception("未找到回调方法");
            }
            // 获取interface
            $interface = $this->obtainApiInterface($this->api);
            // 执行后续操作
            $this->executeCallable($interface);
            // 返回
            return $interface->apiNotifySuccess();

        } catch (Throwable $e) {

            return $this->errorResponse($e);
        }
    }

    /**
     * @param ApiInterface $interface
     * @return void
     */
    protected function executeCallable(ApiInterface $interface): void
    {
        try {
            $this->bean = $interface->apiNotifyLogic($this->api, $this->request)->setApi($this->api);
            // 是否往下执行
            if (!$this->bean->isExecute()) {
                throw new Exception("不往下执行");
            }
            $this->zuhe();
//            // 往下执行
//            match (ApiGroupEnum::identifyByOrderSn($this->bean->getOrderNo())) {
//                default => $this->zhichong(),
//                ApiGroupEnum::CombinationRecharge => $this->zuhe(),
//            };
        } catch (Throwable $e) {
            Log::channel('error')->error('回调执行异常', $this->throwable($e, [
                'request'   => $this->request->toArray(),
                'api'       => $this->api->toArray(),
            ]));
        }
    }

    /**
     * @return void
     * @throws Throwable
     */
    protected function zuhe(): void
    {
        Db::connection()->transaction(function() {
            /** @var H5CombinedOrders|null $combineOrder 查询组合订单 **/
            $combineOrder = H5CombinedOrders::query()->firstWhere($this->bean->getOrderNoKey(['trade_no', 'other_order']), $this->bean->getOrderNo());
            if (!$combineOrder) {
                throw new OrderNotFoundException($this->bean->getOrderNo(), '没有找到组合订单');
            }
            if ($combineOrder->state != 0) {
                throw new OrderIsNotInRechargeException($combineOrder->state == 1 ? '充值成功' : '充值失败');
            }
            // 查询订单
            $order = $this->mainOrder($combineOrder->order_no);
            // 更新组合订单
            $combineOrder->state = $this->bean->isRechargeSuccess() ? 1 : 2;
            $combineOrder->async_msg = array2json($this->request->all());
            $combineOrder->async_time = date('Y-m-d H:i:s');
            $combineOrder->{$this->bean->isRechargeSuccess() ? 'success_time' : 'error_time'} = $combineOrder->async_time;
            $combineOrder->error_msg = $this->bean->isRechargeSuccess() ? '' : $this->bean->getRechargeErrorMessage();
            if (!$combineOrder->save()) {
                throw new Exception("组合订单更新状态失败");
            }
            // 入队
            ZuheJob::dispatch($order)->onQueue('zuhe-execute')->afterCommit()->afterResponse();
        });
    }
    /**
     * @return void
     * @throws Exception
     */
    protected function zhichong(): void
    {
        // 插入队列
        $this->pushNotifyJob(
            $this->mainOrder( $this->bean->getOrderNo(), $this->bean->getOrderNoKey()),
            $this->bean->isRechargeSuccess(),
            $this->bean->isRechargeSuccess() ? '' : $this->bean->getRechargeErrorMessage(),
        );
    }

    /**
     * @param string $orderNo
     * @param string $orderKey
     * @return XnBatchOrder
     * @throws Exception
     */
    protected function mainOrder(string $orderNo, string $orderKey = 'orderNum'): XnBatchOrder
    {
        /** @var XnBatchOrder|null $order  **/
        $order = XnBatchOrder::query()->where($orderKey, $orderNo)->first();
        if (!$order) {
            throw new OrderNotFoundException($this->bean->getOrderNoKey());
        }
        if (in_array($order->recharge_status, [1, 2]) ) {
            throw new OrderIsNotInRechargeException($order->recharge_status == 1 ? '充值成功' : '充值失败');
        }
        return $order;
    }

    /**
     * @param XnBatchOrder $order
     * @param bool $result
     * @param string $errorMessage
     * @return void
     */
    protected function pushNotifyJob(XnBatchOrder $order, bool $result, string $errorMessage = '充值失败'): void
    {
        OrderCallbackNotify::dispatch($order, $result, $errorMessage,$this->bean->getCami())->onQueue('h5_api_notify')->afterCommit()->afterResponse();
    }

    /**
     * @param Throwable $e
     * @param array $merge
     * @return array
     */
    protected function throwable(Throwable $e, array $merge = []): array
    {
        $data = [
            'url'       => $this->request->getUri(),
            'request'   => $this->request->toArray(),
            'error'     => error2array($e),
        ];
        return array_merge($data, $merge);
    }

    /**
     * @param Throwable $e
     * @return JsonResponse
     */
    protected function errorResponse(Throwable $e): JsonResponse
    {
        Log::error('回调异常', $this->throwable($e));
        return response()->json(['code' => 500, 'message' => $e->getMessage()]);
    }
}
